﻿
using System.Diagnostics;
namespace Teal.Compiler {

    /// <summary>
    /// 表示一个成员（如方法、字段、类型、包等）定义。
    /// </summary>
    public abstract partial class MemberDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public virtual void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {
            // 普通成员不存在子成员，在父容器搜索。
            container.bindMember(memberName, genericArgumentCount, ref result);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的成员。
        /// </summary>
        /// <param name="container">绑定所在的容器。</param>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <param name="result">存储绑定的结果。</param>
        public void bindMember(NamespaceReference container, string memberName, int genericArgumentCount, ref MemberBindResult result) {

            if (bindMemberFor(container, memberName, genericArgumentCount, ref result)) {
                return;
            }

            // 查找继承的成员。
            var containerType = container as TypeReference;
            if (containerType != null) {

                // 解析基类时，基类可能未解析
                //
                // class A : B.D {} // B 的基类未解析。
                // class B : C{}
                // class C { class D {}  }
                //
                // 解析 B.D 的时候，需要解析 B 的基类
                // 而此次 B 未解析。

                // 确保基类型已解析。
                if (containerType.definition != null) {
                    containerType.definition.resolveBaseTypes();
                }

                while ((containerType = containerType.baseClass) != null) {
                    if (bindMemberFor(containerType, memberName, genericArgumentCount, ref result)) {
                        return;
                    }
                }
            }

        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的成员。
        /// </summary>
        /// <param name="container">绑定所在的容器。</param>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <param name="result">存储绑定的结果。</param>
        /// <returns>如果绑定成功则返回 true。</returns>
        protected bool bindMemberFor(NamespaceReference container, string memberName, int genericArgumentCount, ref MemberBindResult result) {

            var found = container.getMember(memberName);
            if (found != null) {
                result.found = found;

                do {
                    if (found.matchGenericArgumentCount(genericArgumentCount)) {
                        result.found = found;

                        if (!ResolveHelper.canAccess(this, found)) {
                            result.type = MemberBindResultType.accessDenied;
                            return false;
                        }

                        if (found.memberType == MemberType.errorType) {
                            result.type = MemberBindResultType.ambiguous;
                            return false;
                        }

                        result.type = MemberBindResultType.success;
                        return true;
                    }
                } while ((found = found.next) != null);

                result.type = MemberBindResultType.genericNotMatched;
            }

            return false;
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public virtual ISymbol bindAllMembers(string memberName, int genericArgumentCount) {
            // 普通成员不存在子成员，在父容器搜索。
            return container.bindAllMembers(memberName, genericArgumentCount);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="container">绑定所在的容器。</param>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <param name="fliterProtectedMembers">是否过滤 protected 成员。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public ISymbol bindAllMembers(NamespaceReference container, string memberName, int genericArgumentCount, bool fliterProtectedMembers) {

            //// 如果容器不是类型，则直接绑定所有成员。
            //var containerType = container as MemberContainerReference;
            //if (containerType == null) {
            //    return bindAllMembersFor(container, memberName, genericArgumentCount);
            //}

            //// 查找类型非扩展成员。
            //var members = containerType.getAllMembers(memberName, genericArgumentCount);

            //// 删除其中的 private 和 protected 成员。
            //if (members != null) {
            //    members = members.findAll(member => {
            //        if (fliterProtectedMembers && member.modifiers.hasFlag(Modifiers.@protected)) {
            //            return false;
            //        }
            //        return ResolveHelper.canAccess(this, member);
            //    });
            //}

            //// 查找是否有扩展成员。
            //var extensions = containerType.getAllExtensions();
            //if (extensions != null) {

            //    // 找出扩展中适用的扩展。
            //    MemberReferenceGroup applicableExtensionMembers = null;
            //    foreach (ExtensionReference extension in extensions) {

            //        // 扩展必须已启用。
            //        if (isExtensionImported(extension) && (extension.targetType == container || extension.targetType.isAssignableFrom(containerType))) {
            //            for (var extensionMember = extension.getMember(memberName); extensionMember != null; extensionMember = extensionMember.next) {

            //                // 扩展成员必须符合泛型要求，必须和非扩展成员不冲突。
            //                if (!extensionMember.modifiers.hasFlag(Modifiers.@private) && extensionMember.matchGenericArgumentCount(genericArgumentCount) && (members == null || ResolveHelper.canOverload(members, members.Count, extensionMember))) {

            //                    if (applicableExtensionMembers == null) {
            //                        applicableExtensionMembers = referenceGroup.alloc();
            //                    } else {

            //                        // 检测扩展成员是否被子类扩展成员覆盖。
            //                        foreach (var mergedMember in applicableExtensionMembers) {
            //                            if (mergedMember.hasSameSignature(extensionMember) && ((ExtensionReference)mergedMember.parentContainer).targetType.isAssignableFrom(((ExtensionReference)extensionMember.parentContainer).targetType)) {
            //                                goto end;
            //                            }
            //                        }

            //                    }

            //                    applicableExtensionMembers.Add(extensionMember);

            //                end:
            //                    ;
            //                }
            //            }
            //        }
            //    }

            //    // 如果存在扩展成员，则返回原成员和扩展成员。
            //    if (applicableExtensionMembers != null) {
            //        if (members != null) {
            //            applicableExtensionMembers.AddRange(members);
            //        }
            //        return applicableExtensionMembers;
            //    }

            //}

            //return members;

            throw new Unreachable();

        }

        /// <summary>
        /// 判断当前定义能否调用指定的扩展引用。
        /// </summary>
        /// <param name="memberDefinition">要处理的成员定义。</param>
        /// <param name="extension">要判断的扩展引用。</param>
        /// <returns></returns>
        private bool isExtensionImported(NamespaceReference extension) {

            // 检查修饰符。
            if (!ResolveHelper.canAccess(this, extension)) {
                return false;
            }

            // 属于相同的命名空间。
            if (reference.isNestedChildOf(extension.container)) {
                return true;
            }

            // import 列表里能找到匹配项。
            return containerSourceUnit.isImported(extension);

        }

        /// <summary>
        /// 在当前成员上下文绑定指定非类型容器和名称对应的所有成员。
        /// </summary>
        /// <param name="container">绑定所在的容器。</param>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        protected ISymbol bindAllMembersFor(NamespaceReference container, string memberName, int genericArgumentCount) {
            var builder = new MemberReferenceGroupBuilder();
            for (var member = container.getMember(memberName); member != null; member = member.next) {
                if (member.matchGenericArgumentCount(genericArgumentCount) && ResolveHelper.canAccess(this, member)) {
                    builder.add(member);
                }
            }
            return builder.result;
        }

    }

    /// <summary>
    /// 表示一个方法定义。
    /// </summary>
    public partial class MethodDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {
            var found = reference.getGenericParameter(memberName);
            if (found != null) {
                result.found = found;
                if (genericArgumentCount == 0) {
                    result.type = MemberBindResultType.success;
                    return;
                }
                result.type = MemberBindResultType.genericNotMatched;
            }

            container.bindMember(memberName, genericArgumentCount, ref result);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {
            if (genericArgumentCount == 0) {
                var found = reference.getGenericParameter(memberName);
                if (found != null) {
                    return found;
                }
            }
            return container.bindAllMembers(memberName, genericArgumentCount);
        }

    }

    /// <summary>
    /// 表示一个扩展定义。
    /// </summary>
    public partial class ExtensionDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {
            if (bindMemberFor(reference, memberName, genericArgumentCount, ref result)) {
                return;
            }
            container.bindMember(memberName, genericArgumentCount, ref result);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {
            return bindAllMembersFor(reference, memberName, genericArgumentCount) ?? container.bindAllMembers(memberName, genericArgumentCount);
        }

    }

    /// <summary>
    /// 表示一个命名空间定义。
    /// </summary>
    public partial class NamespaceDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {
            if (bindMemberFor(reference, memberName, genericArgumentCount, ref result)) {
                return;
            }
            container.bindMember(memberName, genericArgumentCount, ref result);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {
            return bindAllMembersFor(reference, memberName, genericArgumentCount) ?? container.bindAllMembers(memberName, genericArgumentCount);
        }

    }

    /// <summary>
    /// 表示一个源编译单元。
    /// </summary>
    public partial class SourceUnit {

        /// <summary>
        /// 判断当前源码下是否已导入指定的成员。
        /// </summary>
        /// <param name="memberContainer"></param>
        /// <returns></returns>
        public bool isImported(NamespaceReference memberContainer) {
            if (_importNamespaces != null) {
                foreach (var importModule in _importNamespaces) {
                    if (importModule.members.ContainsValue(memberContainer)) {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {

            // 可能由于挎包引入导致当前源码的 imports 未定义。
            resolveImports();

            MemberReference found;

            // 在导入别名列表查找。
            if (_importAliases != null && _importAliases.TryGetValue(memberName, out found)) {
                result.found = found;
                if (found.matchGenericArgumentCount(genericArgumentCount)) {
                    result.type = MemberBindResultType.success;
                    return;
                }
                result.type = MemberBindResultType.genericNotMatched;
            }

            // 在包内直接查找。
            container.bindMember(memberName, genericArgumentCount, ref result);
            if (result.type == MemberBindResultType.success) {
                return;
            }

            // 在导入命名空间查找。
            found = null;
            foreach (var importNamespace in _importNamespaces) {
                if (bindMemberFor(importNamespace, memberName, genericArgumentCount, ref result)) {
                    // 找到两个匹配项，则返回错误。
                    if (found != null) {
                        result.alt = found;
                        result.type = MemberBindResultType.ambiguous;
                        return;
                    }

                    found = result.found;
                }
            }
            if (found != null) {
                result.found = found;
                result.type = MemberBindResultType.success;
            }

        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {

            MemberReference found;

            // 在导入别名列表查找。
            if (_importAliases != null && _importAliases.TryGetValue(memberName, out found) && found.matchGenericArgumentCount(genericArgumentCount)) {
                return found;
            }

            // 在包内直接查找。
            var result = container.bindAllMembers(memberName, genericArgumentCount);

            // 在导入模块内查找。
            if (result == null && _importNamespaces != null) {
                var builder = new MemberReferenceGroupBuilder();
                foreach (var importModule in _importNamespaces) {
                    for (var member = importModule.getMember(memberName); member != null; member = member.next) {
                        if (member.matchGenericArgumentCount(genericArgumentCount) && ResolveHelper.canAccess(this, member)) {
                            builder.add(member);
                        }
                    }
                }
                result = builder.result;
            }

            return result;
        }

    }

    /// <summary>
    /// 表示一个模块。
    /// </summary>
    public partial class ModuleDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {
            bindMemberFor(reference, memberName, genericArgumentCount, ref result);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {
            return bindAllMembersFor(reference, memberName, genericArgumentCount);
        }

    }

    /// <summary>
    /// 表示一个枚举定义。
    /// </summary>
    public partial class EnumDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="result">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult result) {
            var found = reference.getMember(memberName);
            if (found != null) {
                result.found = found;
                if (genericArgumentCount == 0) {
                    result.type = MemberBindResultType.success;
                    return;
                }
                result.type = MemberBindResultType.genericNotMatched;
            }

            container.bindMember(memberName, genericArgumentCount, ref result);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {

            // 在枚举成员列表查找。
            if (genericArgumentCount == 0) {
                var result = reference.getMember(memberName);
                if (result != null) {
                    return result;
                }
            }

            return container.bindAllMembers(memberName, genericArgumentCount);
        }

    }

    /// <summary>
    /// 表示一个类型（如类、结构、接口）定义。
    /// </summary>
    public abstract partial class TypeDefinition {

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型参数个数。如果不搜索泛型，则传递 0。</param>
        /// <param name="bindResult">存储绑定的结果。</param>
        public override void bindMember(string memberName, int genericArgumentCount, ref MemberBindResult bindResult) {

            var type = reference;

            // 查找泛型参数。泛型参数本身不能和泛型参数同时使用。
            TypeReference found = type.getGenericParameter(memberName);
            if (found != null) {
                bindResult.found = found;
                if (genericArgumentCount == 0) {
                    bindResult.type = MemberBindResultType.success;
                    return;
                }
                bindResult.type = MemberBindResultType.genericNotMatched;
            }

            // 从当前类以及基类直接查找。
            do {
                if (bindMemberFor(type, memberName, genericArgumentCount, ref bindResult)) {
                    return;
                }
            } while ((type = type.baseClass) != null);

            container.bindMember(memberName, genericArgumentCount, ref bindResult);
        }

        /// <summary>
        /// 在当前成员上下文绑定指定容器和名称对应的所有成员。
        /// </summary>
        /// <param name="memberName">要绑定的名称。</param>
        /// <param name="genericArgumentCount">要绑定的泛型形参数。如果不搜索泛型，则传递 0 。</param>
        /// <returns>如果发现一个绑定结果，则返回相应的成员引用，如果发现多个绑定结果，则返回包含所有结果的成员组，否则返回 null。</returns>
        public override ISymbol bindAllMembers(string memberName, int genericArgumentCount) {

            //var type = reference;

            //// 查找泛型参数。泛型参数本身不能和泛型参数同时使用。
            //if (genericArgumentCount == 0) {
            //    var result = type.getGenericParameter(memberName);
            //    if (result != null) {
            //        return result;
            //    }
            //}

            //// 查找展开的成员列表。
            //var members = type.getAllMembers(memberName, genericArgumentCount);
            //if (members != null) {
            //    return members;
            //}

            return container.bindAllMembers(memberName, genericArgumentCount);
        }

    }

    /// <summary>
    /// 表示成员绑定的结果。
    /// </summary>
    [DebuggerDisplay("type={type} found={found} alt={alt}")]
    public struct MemberBindResult {

        /// <summary>
        /// 获取当前绑定的结果类型。
        /// </summary>
        public MemberBindResultType type;

        /// <summary>
        /// 存储当前绑定的结果。
        /// </summary>
        public MemberReference found;

        /// <summary>
        /// 存储当前绑定的结果。
        /// </summary>
        public MemberReference alt;

    }

    /// <summary>
    /// 表示对绑定结果类型的枚举。
    /// </summary>
    public enum MemberBindResultType {

        /// <summary>
        /// 表示成员未找到。
        /// </summary>
        notFound,

        /// <summary>
        /// 表示成员没有访问权限。
        /// </summary>
        accessDenied,

        /// <summary>
        /// 表示绑定发生歧义。
        /// </summary>
        ambiguous,

        /// <summary>
        /// 表示泛型参数不匹配。
        /// </summary>
        genericNotMatched,

        /// <summary>
        /// 表示绑定成功。
        /// </summary>
        success,

    }

}
